19e08a
@@ -21,8 +21,6 @@
import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -103,15 +101,19 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 			@Override
 			public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
 
-				if (persistentProperty.isEntity()) {
-					indexInformation.addAll(resolveIndexForClass(persistentProperty.getActualType(),
-							persistentProperty.getFieldName(), root.getCollection(), guard));
-				}
+				try {
+					if (persistentProperty.isEntity()) {
+						indexInformation.addAll(resolveIndexForClass(persistentProperty.getActualType(),
+								persistentProperty.getFieldName(), root.getCollection(), guard));
+					}
 
-				IndexDefinitionHolder indexDefinitionHolder = createIndexDefinitionHolderForProperty(
-						persistentProperty.getFieldName(), root.getCollection(), persistentProperty);
-				if (indexDefinitionHolder != null) {
-					indexInformation.add(indexDefinitionHolder);
+					IndexDefinitionHolder indexDefinitionHolder = createIndexDefinitionHolderForProperty(
+							persistentProperty.getFieldName(), root.getCollection(), persistentProperty);
+					if (indexDefinitionHolder != null) {
+						indexInformation.add(indexDefinitionHolder);
+					}
+				} catch (CyclicPropertyReferenceException e) {
+					LOGGER.warn(e.getMessage());
 				}
 			}
 		});
@@ -350,7 +352,7 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 	 * 
 	 * @author Christoph Strobl
 	 */
-	private static class CycleGuard {
+	static class CycleGuard {
 
 		private final Map<String, List<Path>> propertyTypeMap;
 
@@ -362,6 +364,7 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 		 * @param property The property to inspect
 		 * @param path The path under which the property can be reached.
 		 * @throws CyclicPropertyReferenceException in case a potential cycle is detected.
+		 * @see Path#cycles(MongoPersistentProperty, String)
 		 */
 		void protect(MongoPersistentProperty property, String path) throws CyclicPropertyReferenceException {
 
@@ -372,7 +375,7 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 
 				for (Path existingPath : paths) {
 
-					if (existingPath.cycles(property)) {
+					if (existingPath.cycles(property, path)) {
 						paths.add(new Path(property, path));
 						throw new CyclicPropertyReferenceException(property.getFieldName(), property.getOwner().getType(),
 								existingPath.getPath());
@@ -380,7 +383,6 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 				}
 
 				paths.add(new Path(property, path));
-
 			} else {
 
 				ArrayList<Path> paths = new ArrayList<Path>();
@@ -393,7 +395,30 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 			return property.getOwner().getType().getSimpleName() + ":" + property.getFieldName();
 		}
 
-		private static class Path {
+		/**
+		 * Path defines the property and its full path from the document root. <br />
+		 * A {@link Path} with {@literal spring.data.mongodb} would be created for the property {@code Three.mongodb}.
+		 * 
+		 * <pre>
+		 * <code>
+		 * &#64;Document
+		 * class One {
+		 *   Two spring;
+		 * }
+		 * 
+		 * class Two {
+		 *   Three data;
+		 * }
+		 * 
+		 * class Three {
+		 *   String mongodb;
+		 * }
+		 * </code>
+		 * </pre>
+		 * 
+		 * @author Christoph Strobl
+		 */
+		static class Path {
 
 			private final MongoPersistentProperty property;
 			private final String path;
@@ -408,17 +433,23 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 				return path;
 			}
 
-			boolean cycles(MongoPersistentProperty property) {
-
-				Pattern pattern = Pattern.compile("\\b" + Pattern.quote(property.getFieldName()) + "\\b");
-				Matcher matcher = pattern.matcher(path);
-
-				int count = 0;
-				while (matcher.find()) {
-					count++;
+			/**
+			 * Checks whether the given property is owned by the same entity and if it has been already visited by a subset of
+			 * the current path. Given {@literal foo.bar.bar} cycles if {@literal foo.bar} has already been visited and
+			 * {@code class Bar} contains a property of type {@code Bar}. The previously mentioned path would not cycle if
+			 * {@code class Bar} contained a property of type {@code SomeEntity} named {@literal bar}.
+			 * 
+			 * @param property
+			 * @param path
+			 * @return
+			 */
+			boolean cycles(MongoPersistentProperty property, String path) {
+
+				if (!property.getOwner().equals(this.property.getOwner())) {
+					return false;
 				}
 
-				return count >= 1 && property.getOwner().getType().equals(this.property.getOwner().getType());
+				return path.contains(this.path);
 			}
 		}
 	}
@@ -448,8 +479,8 @@
public class MongoPersistentEntityIndexResolver implements IndexResolver {
 		 */
 		@Override
 		public String getMessage() {
-			return String.format("Found cycle for field '%s' in type '%s' for path '%s'", propertyName, type.getSimpleName(),
-					dotPath);
+			return String.format("Found cycle for field '%s' in type '%s' for path '%s'", propertyName,
+					type != null ? type.getSimpleName() : "unknown", dotPath);
 		}
 	}
 
